﻿using Abp.Timing;
using AutoMapper;
using DotNetCore.CAP;
using Hicap.QRCodeWarehouse.Processor.Const;
using Hicap.QRCodeWarehouse.Processor.Manager;
using Hicap.QRCodeWarehouse.Processor.Model;
using Serilog;
using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace Hicap.QRCodeWarehouse.Processor.Service
{
    /// <summary>
    /// Taken qrcodes service
    /// </summary>
    public class CodeTakenService : ServiceBase, ICodeTakenService, ICapSubscribe
    {
        private readonly ICodeTakenManager _codeTakenManager;
        private readonly ICapPublisher _capBus;

        public CodeTakenService(ICodeTakenManager codeTakenManager, ICapPublisher capBus)
        {
            _codeTakenManager = codeTakenManager;
            _capBus = capBus;
        }

        /// <summary>
        /// Reponse taken codes data file action
        /// </summary>
        /// <param name="input">TakeFileCommandDto</param>
        /// <returns></returns>
        [CapSubscribe(MessageQueueChanelConst.CodeTakenServiceAction, Group = SysConst.SysName)]
        public async Task<ActionResult> DispatchCodeTakenAction(TakeFileCommandDto input)
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            try
            {
                //taken config
                CodeTakenConfig config = Mapper.Map<CodeTakenConfig>(input);

                //taken file output
                TakeFileFeedbackDto feedback = new TakeFileFeedbackDto()
                {
                    Handle = input.Handle,
                    ProductId = input.ProductId,
                    ProductCode = input.ProductCode,
                    GenerationRuleType = input.GenerationRuleType,
                    Progress = 1,
                    Status = GenerationStatus.Running,
                    FileName = input.FileName,
                    UserId = input.UserId
                };

                //make data file
                FileInfo result = await _codeTakenManager.GenDataFile(config,
                    async x =>
                    {
                        //in pending
                        if (x != 1)
                        {
                            //progress
                            feedback.Progress = x;

                            //publish message
                            await PublishMessageAsync(feedback, config);
                        }
                    });

                //get file total count
                int totalDownloadCount = await _codeTakenManager.GetTotoalDownloadCount(config);

                //when complete data file, publish complete message to client
                await _capBus.PublishAsync(MessageQueueChanelConst.CodeTakenServiceFeedBack,
                    new TakeFileFeedbackDto()
                    {
                        Handle = input.Handle,
                        ProductId = input.ProductId,
                        ProductCode = input.ProductCode,
                        GenerationRuleType = input.GenerationRuleType,
                        Progress = 1,
                        Status = GenerationStatus.Complete,
                        FileName = input.FileName,
                        //saved path in ftp server
                        ResultFile = result,
                        UserId = input.UserId,
                        TotalDownload = totalDownloadCount + result.FileRecoredCount
                    }, MessageQueueChanelConst.CodeTakenServiceFeedBack + ".End");

                Log.Information($"Taken file handle[{input.Handle}] - data file {input.FileName} is Completed");

                return new ActionResult(MessageQueueChanelConst.CodeTakenServiceAction, true, watch.ElapsedMilliseconds, Clock.Now, input);
            }
            catch (Exception e)
            {
                return new ActionResult(MessageQueueChanelConst.CodeTakenServiceAction, false, watch.ElapsedMilliseconds, Clock.Now, input, e);
            }
        }

        /// <summary>
        /// publish template
        /// </summary>
        /// <param name="feedback">TakeFileFeedbackDto</param>
        /// <param name="input">CodeTakenConfig</param>
        /// <returns></returns>
        private async Task PublishMessageAsync(TakeFileFeedbackDto feedback, CodeTakenConfig input)
        {
            await _capBus.PublishAsync(MessageQueueChanelConst.CodeTakenServiceFeedBack, feedback, MessageQueueChanelConst.CodeTakenServiceFeedBack + ".End");

            Log.Information($"Taken file handle[{input.Handle}] - data file {input.FileName} progress percent :{feedback.Progress:p3}");
        }

        [CapSubscribe(MessageQueueChanelConst.CodeTakenServiceFeedBack + ".End", Group = SysConst.SysName)]
        public void FinalFeedBackMessage(ActionResult result)
        {
            if (result.IsSuccessed)
                Log.Information($"FeedBack Finished:{MessageQueueChanelConst.CodeTakenServiceFeedBack}--{result}");
            else
                Log.Error($"FeedBack have a Error:{MessageQueueChanelConst.CodeTakenServiceFeedBack}--{result}");
        }
    }
}